package com.wxzz.elearing.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.service.additional.update.impl.UpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.wxzz.elearing.user.dto.*;
import com.wxzz.elearing.user.entity.*;
import com.wxzz.elearing.user.mapper.*;
import com.wxzz.elearing.user.service.IEnterpriseImproveService;
import com.wxzz.elearing.user.service.IWxUserService;
import com.wxzz.elearing.user.service.openfeign.*;
import com.wxzz.elearing.user.vo.*;
import com.wxzz.elearning.common.aop.Idempotent;
import com.wxzz.elearning.common.constants.RedisConstants;
import com.wxzz.elearning.common.constants.WxLoginConstants;
import com.wxzz.elearning.common.dto.FeignStudyTimeDto;
import com.wxzz.elearning.common.dto.FeignWxUserDto;
import com.wxzz.elearning.common.exception.ServiceException;
import com.wxzz.elearning.common.utils.AesCbcUtil;
import com.wxzz.elearning.common.utils.ExcelUtils;
import com.wxzz.elearning.common.utils.HttpRequest;
import com.wxzz.elearning.common.utils.OpenFeignUtil;
import com.wxzz.elearning.common.vo.JgPageVo;
import com.wxzz.elearning.common.vo.ReturnVO;
import feign.FeignException;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Base64Utils;
import org.springframework.web.multipart.MultipartFile;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletResponse;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.security.spec.AlgorithmParameterSpec;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class WxUserServiceImpl extends ServiceImpl<WxUserMapper, WxUser> implements IWxUserService {

    private Logger logger = LoggerFactory.getLogger(WxUserServiceImpl.class);

    @Autowired
    private WxUserMapper wxUserMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public ReturnVO<Map> wxLogin(WxLoginDto wxLoginDto) throws Exception {
        logger.info("请求数据是==================" + wxLoginDto);
        String code = wxLoginDto.getCode();
        String encryptedData = wxLoginDto.getEncryptedData();
        String iv = wxLoginDto.getIv();
        ReturnVO<Map> returnVO = new ReturnVO();
        Map<String, Object> map = new HashMap<>();
        // 请求参数
        String params = "appid=" + WxLoginConstants.WX_APPID + "&secret=" + WxLoginConstants.WX_SECRET + "&js_code=" + code + "&grant_type=" + WxLoginConstants.WX_GRANT_TYPE;
        // 发送请求
        String sr = HttpRequest.sendGet(WxLoginConstants.WX_GET_SESSION_KEY_URL, params);
        logger.info("发送请求微信返回数据是====================" + sr);
        // 解析相应内容（转换成json对象）
        JSONObject json = JSONObject.parseObject(sr);
        String session_key = json.get("session_key").toString();
        String user_info = AesCbcUtil.decrypt(encryptedData, session_key, iv, "UTF-8");
        //将wx_user缓存redis中
        WxUser temp = null;
        if (null != user_info && user_info.length() > 0) {
            JSONObject userInfoJSON = JSONObject.parseObject(user_info);
            String openid = json.getString("openid");
            String nickname = userInfoJSON.getString("nickName");
            String icon = userInfoJSON.getString("avatarUrl");
            String gender = userInfoJSON.getString("gender");
            Optional<WxUser> wxUserOptional = wxUserMapper.selectWxUserByOpenid(openid);
            if (!wxUserOptional.isPresent()) {
                //首次登录
                WxUser wxUser = new WxUser();
                wxUser.setIcon(icon);
                wxUser.setOpenid(openid);
                wxUser.setNickname(nickname);
                wxUser.setSessionKey(session_key);
//                if ("0".equals(gender)) {
//                    wxUser.setSex(1);
//                }
//                if ("1".equals(gender)) {
//                    wxUser.setSex(2);
//                }
                wxUser.setSex(Integer.valueOf(gender));
                int insert = wxUserMapper.insert(wxUser);
                if (insert == 0) {
                    throw new ServiceException("用户授权新增失败");
                }
                temp = wxUserMapper.selectById(wxUser.getId());
            } else {
                //如果已存在直接登录
                temp = wxUserOptional.get();
                //更新session_key
                temp.setSessionKey(session_key);
            }
            if (StringUtils.isNotBlank(temp.getToken())) {
                if (redisTemplate.hasKey(temp.getToken())) {
                    //删除废弃token
                    redisTemplate.delete(temp.getToken());
                }
            }
            //存放新的token
            String token = RedisConstants.WX_TOKEN + UUID.randomUUID().toString();
            temp.setToken(token);
            redisTemplate.opsForValue().set(token, JSONObject.toJSONString(temp), 60 * 60 * 24 * 10 * 30, TimeUnit.SECONDS);
            wxUserMapper.updateById(temp);
            map.put("wxUser", temp);
            map.put("token", token);
            returnVO.setCode("200");
            returnVO.setMessage("微信用户授权成功");
            returnVO.setData(map);
        } else {
            throw new ServiceException("授权失败解析的user_info为====>" + user_info);
        }
        return returnVO;
    }

    @Override
    public ReturnVO bindPhone(Long wxUserId, BingPhoneDto bingPhoneDto) throws Exception {
        String phone = null;
        //查出该用户对象
        WxUser wxUser = wxUserMapper.selectById(wxUserId);
        //一键获取验证手机号
        if (bingPhoneDto.getType() == 0) {
            logger.info("一键获取验证手机号请求数据是====>" + bingPhoneDto);
            // 解析相应内容（转换成json对象）
            byte[] encrypData = Base64Utils.decodeFromString(bingPhoneDto.getEncryptedData());
            byte[] ivData = Base64Utils.decodeFromString(bingPhoneDto.getIv());
            byte[] sessionKey = Base64Utils.decodeFromString(wxUser.getSessionKey());
            AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivData);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec keySpec = new SecretKeySpec(sessionKey, "AES");
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);// 设置为解密模式
            String resultString = new String(cipher.doFinal(encrypData), "UTF-8");
            JSONObject object = JSONObject.parseObject(resultString);
            phone = object.getString("phoneNumber");
        }
        //验证码验证手机号
        if (bingPhoneDto.getType() == 1) {
            phone = bingPhoneDto.getPhone();
            if (StringUtils.isBlank(phone)) {
                throw new ServiceException("手机号不能为空");
            }
            String redisCode = redisTemplate.opsForValue().get(RedisConstants.PHONE_CODE + phone);
            if (StringUtils.isBlank(bingPhoneDto.getCode())) {
                throw new ServiceException("验证码不能为空");
            }
            if (StringUtils.isBlank(redisCode)) {
                throw new ServiceException("验证码已过期");
            }
            if (!redisCode.equals(bingPhoneDto.getCode())) {
                throw new ServiceException("验证码错误");
            }
        }
        Optional<WxUser> appWxUser = wxUserMapper.selectWxUserByPhoneAndOpenidIsNotNull(phone);
        if (appWxUser.isPresent()) {
            throw new ServiceException("该手机号已经绑定其他用户");
        }
        //查询该用户是否已绑定手机号
        if (StringUtils.isNotBlank(wxUser.getPhone())) {
            throw new ServiceException("您已经绑定手机号:" + wxUser.getPhone());
        }
        //查询后台是否有导入的该手机号
        Optional<WxUser> adminWxUser = wxUserMapper.selectWxUserByPhoneAndOpenidIsNull(phone);
        if (adminWxUser.isPresent()) {
            //如果存在 将后台导入的账号与小程序账号绑定
            // BeanUtils.copyProperties(adminWxUser.get(),wxUser);
            wxUser.setPhone(adminWxUser.get().getPhone());
//            wxUser.setDepartmentId(adminWxUser.get().getDepartmentId());
//            wxUser.setGroupId(adminWxUser.get().getGroupId());
//            wxUser.setJobId(adminWxUser.get().getJobId());
            wxUser.setNickname(adminWxUser.get().getNickname());
            wxUser.setEnterpriseId(adminWxUser.get().getEnterpriseId());
            wxUser.setIcon(adminWxUser.get().getIcon());
            wxUser.setEnterpriseOrganizationId(adminWxUser.get().getEnterpriseOrganizationId());
            wxUser.setEnterpriseIdentityId(adminWxUser.get().getEnterpriseIdentityId());
            wxUserMapper.deleteById(adminWxUser.get().getId());
        } else {
            //不存在直接绑定手机号
            wxUser.setPhone(phone);
        }
        wxUserMapper.updateById(wxUser);
        return new ReturnVO("绑定成功", phone);
    }

    @Autowired
    private EnterpriseMapper enterpriseMapper;

    @Override
    public ReturnVO<WxUser> getWxUser(Long wxUserId) {
        WxUser wxUser = wxUserMapper.selectById(wxUserId);
        Optional.ofNullable(wxUser).orElseThrow(() -> new ServiceException("该用户不存在"));
        Enterprise enterprise = enterpriseMapper.selectById(wxUser.getEnterpriseId());
        if (enterprise != null) {
            wxUser.setEnterpriseName(enterprise.getEnterpriseName());
            //查询部门职位
            FeignWxUserDto feignWxUserDto = selectFeignWxUserDtoByWxUserId(wxUser.getId());
            wxUser.setOrganizationName(feignWxUserDto.getOrganizationName());
            wxUser.setLastOrganizationName(feignWxUserDto.getLastOrganizationName());
            wxUser.setIdentityName(feignWxUserDto.getIdentityName());
            wxUser.setEnterpriseServicePhone(enterprise.getEnterpriseServicePhone());
        }
        return new ReturnVO("获取微信用户信息成功", wxUser);
    }

    @Override
    public ReturnVO<Enterprise> getEnterprise(Long wxUserId) {
        WxUser wxUser = wxUserMapper.selectById(wxUserId);
        Optional.ofNullable(wxUser).orElseThrow(() -> new ServiceException("该用户不存在"));
        Enterprise enterprise = enterpriseMapper.selectById(wxUser.getEnterpriseId());
        return new ReturnVO("用户企业信息获取成功", enterprise);
    }

    @Override
    public ReturnVO sendCode(String phone) {
        String code = redisTemplate.opsForValue().get(phone);
        if (StringUtils.isNotBlank(code)) {
            throw new ServiceException("操作频繁,请稍后再试");
        }
        redisTemplate.opsForValue().set(RedisConstants.PHONE_CODE + phone, "123123", 60 * 1, TimeUnit.SECONDS);
        return new ReturnVO("验证码发送成功", null);
    }

    @Override
    public void exportExcel(HttpServletResponse response) throws IOException {
        long start = System.currentTimeMillis();
        List<WxUser> wxUsers = wxUserMapper.selectList(new QueryWrapper<>());
        for (WxUser wxUser : wxUsers) {
            FeignWxUserDto feignWxUserDto = selectFeignWxUserDtoByWxUserId(wxUser.getId());
            wxUser.setOrganizationName(feignWxUserDto.getOrganizationName());
            wxUser.setLastOrganizationName(feignWxUserDto.getLastOrganizationName());
            wxUser.setIdentityName(feignWxUserDto.getIdentityName());
        }
        ExcelUtils.exportExcel(wxUsers, "员工信息表", "员工信息", WxUser.class, "员工信息", response);
        logger.debug("导出excel所花时间：" + (System.currentTimeMillis() - start));
    }

    @Transactional
    @Override
    public ReturnVO importExcel(String token, MultipartFile file) throws IOException {
        //接口幂等处理
        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(RedisConstants.WX_USER_IMPORT + token, token, 5, TimeUnit.SECONDS);
        if (!Boolean.TRUE.equals(aBoolean)) {
            throw new ServiceException("操作太频繁,请5秒后再试");
        }
        long start = System.currentTimeMillis();
        List<WxUser> wxUsers = ExcelUtils.importExcel(file, WxUser.class);
        for (int i = 0; i < wxUsers.size(); i++) {
            Optional<WxUser> wxUserOptional = wxUserMapper.selectWxUserByPhone(wxUsers.get(i).getPhone());
            if (wxUserOptional.isPresent() && wxUserOptional.get().getEnterpriseId() != 0) {
                throw new ServiceException("第" + (i + 1) + "条数据手机号已拥有企业");
            }
            String s = redisTemplate.opsForValue().get(token);
            JSONObject jsonObject = JSONObject.parseObject(s);
            wxUsers.get(i).setEnterpriseId(jsonObject.getLong("enterpriseId"));
            WxUser wxUser = wxUsers.get(i);
            if (wxUserOptional.isPresent()) {
                wxUser.setId(wxUserOptional.get().getId());
                wxUser.setEnterpriseId(jsonObject.getLong("enterpriseId"));
                wxUserMapper.updateById(wxUser);
            } else {
                wxUserMapper.insert(wxUser);
            }
        }
        logger.debug(wxUsers.toString());
        logger.debug("导入excel所花时间：" + (System.currentTimeMillis() - start));
        return new ReturnVO("导入成功", wxUsers);
    }

    @Autowired
    private ICurriculumApiFeign curriculumApiFeign;

    @SneakyThrows
    @Override
    public ReturnVO<JgPageVo<List<WxUser>>> listWxUser(HttpServletResponse response, Integer type, WxUserDto wxUserDto, Long enterpriseId) {
        PageHelper.startPage(wxUserDto.getCurPage(), wxUserDto.getMaxPage());
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.orderByDesc("create_time");
        if (StringUtils.isNotBlank(wxUserDto.getNickname())) {
            queryWrapper.like("nickname", wxUserDto.getNickname() + "%");
        }
        if (StringUtils.isNotBlank(wxUserDto.getPhone())) {
            queryWrapper.like("phone", wxUserDto.getPhone());
        }
        if (wxUserDto.getEnterpriseOrganizationId() != null) {
            queryWrapper.eq("enterprise_organization_id", wxUserDto.getEnterpriseOrganizationId());
        }
        if (wxUserDto.getEnterpriseIdentityId() != null) {
            queryWrapper.eq("enterprise_identity_id", wxUserDto.getEnterpriseIdentityId());
        }
        if (wxUserDto.getStartTime() != null && wxUserDto.getEndTime() != null) {
            queryWrapper.between("create_time", wxUserDto.getStartTime(), wxUserDto.getEndTime());
        }
        //平台用户
        if (type != null && type == 0) {
            queryWrapper.eq("enterprise_id", 0);
        }
        //企业用户
        if (type != null && type == 1) {
            queryWrapper.ne("enterprise_id", 0);
        }
        //根据当前企业身份调用微信用户列表
        if (enterpriseId != null) {
            queryWrapper.eq("enterprise_id", enterpriseId);
        }
        List<WxUser> wxUsers = wxUserMapper.selectList(queryWrapper);
        for (WxUser wxUser : wxUsers) {
            //查询企业名称
            Enterprise enterprise = enterpriseMapper.selectById(wxUser.getEnterpriseId());
            if (type != null && type == 1) {
                if (enterprise != null) {
                    enterprise.setEnterpriseName(enterprise.getEnterpriseName());
                }
            }
            //是否为院长
            if (enterpriseId != null && enterprise != null) {
                if (wxUser.getId().equals(enterprise.getWxUserId())) {
                    wxUser.setIsDean(1);
                }
            }
            //查询部门职位
            FeignWxUserDto feignWxUserDto = selectFeignWxUserDtoByWxUserId(wxUser.getId());
            wxUser.setOrganizationName(feignWxUserDto.getOrganizationName());
            wxUser.setLastOrganizationName(feignWxUserDto.getLastOrganizationName());
            wxUser.setIdentityName(feignWxUserDto.getIdentityName());
            wxUser.setEnterpriseName(feignWxUserDto.getEnterpriseName());
            //统计学习时长
            ReturnVO<String> stringReturnVO = curriculumApiFeign.selectWxUserCurriculumDataByWxUserId(wxUser.getId());
            JSONObject jsonObject = OpenFeignUtil.getJSONObject(stringReturnVO);
            if (jsonObject.getLong("studyTime") != null) {
                wxUser.setStudyTime((double) jsonObject.getLong("studyTime") / (60 * 60));
                wxUser.setTodayStudyTime((double) jsonObject.getLong("todayStudyTime") / (60 * 60));
                wxUser.setFinishClass(jsonObject.getLong("finishClass"));
            }
            //查询星级
            wxUser.setStartLevel(evaluationApiFeign.selectWxUserStart(wxUser.getId()));
        }
        if (wxUserDto.getIsExport() != null && wxUserDto.getIsExport() == 1) {
            ExcelUtils.exportExcel(wxUsers, "微信用户", "微信用户", WxUser.class, "微信用户", response);
            return new ReturnVO("微信用户导出成功", null);
        }
        return new ReturnVO("微信用户列表查询成功", new JgPageVo<>(new PageInfo(wxUsers)));
    }

    @Autowired
    private IEvaluationApiFeign evaluationApiFeign;

    /**
     * @param name 转换前的驼峰式命名的字符串
     * @return 转换后下划线大写方式命名的字符串
     */

    public static String humpToUnderline(String name) {
        StringBuilder result = new StringBuilder();
        if (name != null && name.length() > 0) {
            // 循环处理其余字符
            for (int i = 0; i < name.length(); i++) {
                String s = name.substring(i, i + 1);
                // 在大写字母前添加下划线
                if (s.equals(s.toUpperCase()) && !Character.isDigit(s.charAt(0))) {
                    result.append("_");
                }
                // 其他字符直接转成小写
                result.append(s.toLowerCase());
            }
        }
        return result.toString();
    }

    @Override
    public ReturnVO<List<Long>> listWxUserByMap(Map<String, String> map) {
        QueryWrapper<WxUser> queryWrapper = new QueryWrapper();
//        Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
//        while (iterator.hasNext()){
//            Map.Entry<String, String> next = iterator.next();
//            if(next.getKey().equals("nickname")){
//                queryWrapper.like("nickname",next.getValue());
//            }else {
//                queryWrapper.eq(next.getKey(),next.getValue());
//            }
//        }
//        map.forEach(queryWrapper::eq);
        map.forEach((k, v) -> {
            if ("nickname".equals(k)) {
                queryWrapper.like("nickname", v + "%");
            } else {
                queryWrapper.eq(humpToUnderline(k), v);
            }
        });
        List<WxUser> wxUsers = wxUserMapper.selectList(queryWrapper);
        List<Long> wxUserIds = Lists.newArrayList();
        for (WxUser wxUser : wxUsers) {
            wxUserIds.add(wxUser.getId());
        }
        return new ReturnVO<>("用户列表查询成功", wxUserIds);
    }

    //空值不拷贝
    public static String[] getNullPropertyNames(Object source) {
//        org.springframework.beans.BeanWrapper
        final BeanWrapper src = new BeanWrapperImpl(source);
//        java.beans.PropertyDescriptor
        PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<>();
        for (PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) {
                emptyNames.add(pd.getName());
            }
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }

    @Idempotent
    @Transactional
    @Override
    public ReturnVO saveWxUser(WxUser wxUser) {
        if (wxUser.getEnterpriseOrganizationId() == null || wxUser.getEnterpriseIdentityId() == null) {
            throw new ServiceException("请选择用户的部门和职位");
        }
        if (wxUser.getId() == null) {
            //查询用户是否拥有企业
            WxUser selectOne = wxUserMapper.selectOne(new LambdaQueryWrapper<WxUser>()
                    .eq(WxUser::getPhone, wxUser.getPhone())
                    .ne(WxUser::getEnterpriseId, 0));
            if (selectOne != null) {
                throw new ServiceException("该手机号对应用户已经拥有企业");
            }
            //查询用户是否存在
            WxUser exits = wxUserMapper.selectOne(new LambdaQueryWrapper<WxUser>()
                    .eq(WxUser::getPhone, wxUser.getPhone()));
            if (exits != null) {
                BeanUtils.copyProperties(wxUser, exits, getNullPropertyNames(wxUser));
                wxUserMapper.updateById(exits);
                //赋值
                wxUser.setId(exits.getId());
            } else {
                wxUserMapper.insert(wxUser);
            }
        } else {
            WxUser select = wxUserMapper.selectById(wxUser.getId());
            if (!select.getPhone().equals(wxUser.getPhone())) {
                WxUser selectOne = wxUserMapper.selectOne(new LambdaQueryWrapper<WxUser>()
                        .eq(WxUser::getPhone, wxUser.getPhone())
                        .ne(WxUser::getEnterpriseId, 0));
                Optional.ofNullable(selectOne).orElseThrow(() -> new ServiceException("该手机号对应用户已存在"));
            }
            Optional.ofNullable(select).orElseThrow(() -> new ServiceException("该用户不存在"));
            wxUserMapper.updateById(wxUser);
        }
        WxUser select = wxUserMapper.selectById(wxUser.getId());
        //更新token
        if (StringUtils.isNotBlank(select.getToken())) {
            if (redisTemplate.hasKey(select.getToken())) {
                //删除废弃token
                redisTemplate.delete(select.getToken());
            }
        }
        return new ReturnVO<>("用户添加成功", wxUser.getId());
    }

    @Override
    public ReturnVO<JgPageVo<List<WxUser>>> listCurWxUser(Long enterpriseId, CurWxUserDto curWxUserDto) {
        PageHelper.startPage(curWxUserDto.getCurPage(), curWxUserDto.getMaxPage());
        QueryWrapper<WxUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("create_time");
        queryWrapper.eq("enterprise_id", enterpriseId);
        if (StringUtils.isNotBlank(curWxUserDto.getNickname())) {
            queryWrapper.like("nickname", curWxUserDto.getNickname() + "%");
        }
        List<WxUser> wxUsers = wxUserMapper.selectList(queryWrapper);
        return new ReturnVO("企业用户列表查询成功", new JgPageVo<>(new PageInfo(wxUsers)));
    }

    @Autowired
    private IExamApiFeign examApiFeign;

    @Autowired
    private ICurriculumApiFeign wxUserStudyPlanApiFeign;

    @Autowired
    private ICurriculumApiFeign trainSurveyApiFeign;

    @Override
    public ReturnVO<JgPageVo<List<WxUser>>> listBindWxUser(Long enterpriseId, BindWxUserDto bindWxUserDto) {
        PageHelper.startPage(bindWxUserDto.getCurPage(), bindWxUserDto.getMaxPage());
        QueryWrapper<WxUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("create_time");
        queryWrapper.eq("enterprise_id", enterpriseId);
        if (StringUtils.isNotBlank(bindWxUserDto.getNickname())) {
            queryWrapper.like("nickname", bindWxUserDto.getNickname() + "%");
        }
        if (bindWxUserDto.getEnterpriseOrganizationId() != null) {
            queryWrapper.eq("enterprise_organization_id", bindWxUserDto.getEnterpriseOrganizationId());
        }
        if (bindWxUserDto.getEnterpriseIdentityId() != null) {
            queryWrapper.eq("enterprise_identity_id", bindWxUserDto.getEnterpriseIdentityId());
        }
        List<WxUser> wxUsers = wxUserMapper.selectList(queryWrapper);
        List<Long> wxUserIds = Lists.newArrayList();
        wxUsers.forEach(wxUser -> {
            wxUserIds.add(wxUser.getId());
            FeignWxUserDto feignWxUserDto = selectFeignWxUserDtoByWxUserId(wxUser.getId());
            wxUser.setOrganizationName(feignWxUserDto.getOrganizationName());
            wxUser.setIdentityName(feignWxUserDto.getIdentityName());
        });

        if (bindWxUserDto.getType() != null && bindWxUserDto.getType() == 0) {
            //在线考试
            ReturnVO<List<JSONObject>> listReturnVO = examApiFeign.selectWxUserExam(bindWxUserDto.getCommonId(), wxUserIds);
            if ("200".equals(listReturnVO.getCode())) {
                for (WxUser wxUser : wxUsers) {
                    for (JSONObject datum : listReturnVO.getData()) {
                        if (wxUser.getId().equals(datum.getLong("wxUserId"))) {
                            //如果用户已绑定则勾选
                            wxUser.setIsChoose(Boolean.TRUE);
                        }
                    }
                }
            }
        }
        if (bindWxUserDto.getType() != null && bindWxUserDto.getType() == 4) {
            //学习计划
            ReturnVO<List<JSONObject>> listReturnVO = wxUserStudyPlanApiFeign.selectWxUserStudyPlan(bindWxUserDto.getCommonId(), wxUserIds);
            if ("200".equals(listReturnVO.getCode())) {
                for (WxUser wxUser : wxUsers) {
                    for (JSONObject datum : listReturnVO.getData()) {
                        if (wxUser.getId().equals(datum.getLong("wxUserId"))) {
                            //如果用户已绑定则勾选
                            wxUser.setIsChoose(Boolean.TRUE);
                        }
                    }
                }
            }
        }
        if (bindWxUserDto.getType() != null && bindWxUserDto.getType() == 5) {
            //培训调查
            ReturnVO<List<JSONObject>> listReturnVO = trainSurveyApiFeign.selectWxUserTrainSurvey(bindWxUserDto.getCommonId(), wxUserIds);
            if ("200".equals(listReturnVO.getCode())) {
                for (WxUser wxUser : wxUsers) {
                    for (JSONObject datum : listReturnVO.getData()) {
                        if (wxUser.getId().equals(datum.getLong("wxUserId"))) {
                            //如果用户已绑定则勾选
                            wxUser.setIsChoose(Boolean.TRUE);
                        }
                    }
                }
            }
        }

        return new ReturnVO("企业用户列表查询成功", new JgPageVo<>(new PageInfo(wxUsers)));
    }

    @Autowired
    private AdminUserMapper adminUserMapper;

    @Override
    public ReturnVO<AdminUser> selectAdminUserById(Long adminUserId) {
        AdminUser adminUser = adminUserMapper.selectById(adminUserId);
        return new ReturnVO("后台用户查询成功", adminUser);
    }

    @Override
    public ReturnVO<WxUser> selectWxUserId(Long wxUserId) {
        WxUser wxUser = wxUserMapper.selectById(wxUserId);
        return new ReturnVO("微信用户查询成功", wxUser);
    }

    @Override
    public ReturnVO updateWxUser(UpdateWxUserDto updateWxUserDto) {
        WxUser wxUser = new WxUser();
        if (StringUtils.isBlank(updateWxUserDto.getNickname().trim())) {
            updateWxUserDto.setNickname(null);
        }
        BeanUtils.copyProperties(updateWxUserDto, wxUser);
        wxUserMapper.updateById(wxUser);
        WxUser select = wxUserMapper.selectById(wxUser.getId());
        //更新token
        if (StringUtils.isNotBlank(select.getToken())) {
            if (redisTemplate.hasKey(select.getToken())) {
                //删除废弃token
                redisTemplate.delete(select.getToken());
            }
        }
        //存放新的token
        String token = RedisConstants.WX_TOKEN + UUID.randomUUID().toString();
        select.setToken(token);
        redisTemplate.opsForValue().set(token, JSONObject.toJSONString(select), 60 * 60 * 24 * 10 * 30, TimeUnit.SECONDS);
        return new ReturnVO("用户信息修改成功", wxUser.getId());
    }

    @Autowired
    private WxUserStatisticsMapper wxUserStatisticsMapper;

    @Override
    public ReturnVO saveVisitNum(Long enterpriseId) {
        //接口熔断 防止用户无法打开首页
        try {
            String saveTime = LocalDate.now().toString();
            WxUserStatistics wxUserStatistics = wxUserStatisticsMapper.selectOne(new LambdaQueryWrapper<WxUserStatistics>()
                    .eq(WxUserStatistics::getSaveTime, saveTime)
                    .eq(WxUserStatistics::getEnterpriseId, enterpriseId));
            if (wxUserStatistics == null) {
                wxUserStatistics = new WxUserStatistics();
                wxUserStatistics.setSaveTime(saveTime);
                wxUserStatistics.setVisitNum(1L);
                wxUserStatistics.setEnterpriseId(enterpriseId);
                wxUserStatisticsMapper.insert(wxUserStatistics);
            } else {
                wxUserStatistics.setVisitNum(wxUserStatistics.getVisitNum() + 1);
                wxUserStatisticsMapper.updateById(wxUserStatistics);
            }
        } catch (Exception e) {
            logger.error("访问量统计出现异常:{}", e.getMessage());
            return new ReturnVO("访问成功", null);
        }
        return new ReturnVO("访问成功", null);
    }

    @Autowired
    private EnterpriseOrganizationMapper enterpriseOrganizationMapper;

    @Autowired
    private EnterpriseIdentityMapper enterpriseIdentityMapper;

    @Override
    public FeignWxUserDto selectFeignWxUserDtoByWxUserId(Long wxUserId) {
        FeignWxUserDto feignWxUserDto = new FeignWxUserDto();
        WxUser wxUser = wxUserMapper.selectById(wxUserId);
        if (wxUser == null) {
            return feignWxUserDto;
        }
        BeanUtils.copyProperties(wxUser, feignWxUserDto);
        //查询组织架构
        EnterpriseOrganization enterpriseOrganization = enterpriseOrganizationMapper.selectById(wxUser.getEnterpriseOrganizationId());
        if (enterpriseOrganization != null) {
            feignWxUserDto.setOrganizationName(enterpriseOrganization.getOrganizationName());
        }
        if (enterpriseOrganization != null && enterpriseOrganization.getPid() != null && enterpriseOrganization.getPid() != 0) {
            EnterpriseOrganization last = enterpriseOrganizationMapper.selectById(enterpriseOrganization.getPid());
            feignWxUserDto.setLastOrganizationName(last.getOrganizationName());
        }
        EnterpriseIdentity enterpriseIdentity = enterpriseIdentityMapper.selectById(wxUser.getEnterpriseIdentityId());
        if (enterpriseIdentity != null) {
            feignWxUserDto.setIdentityName(enterpriseIdentity.getIdentityName());
        }
        //查询组织信息
        Enterprise enterprise = enterpriseMapper.selectById(wxUser.getEnterpriseId());
        if (enterprise != null) {
            feignWxUserDto.setEnterpriseName(enterprise.getEnterpriseName());
            feignWxUserDto.setEnterprisePlaceDetail(enterprise.getEnterprisePlaceDetail());
        }
        return feignWxUserDto;
    }

    @Override
    public FeignWxUserDto selectFeignWxUserDtoByDocentId(Long docentId) {
        FeignWxUserDto feignWxUserDto = new FeignWxUserDto();
        Docent docent = docentMapper.selectById(docentId);
        WxUser wxUser = null;
        if (docent != null) {
            wxUser = wxUserMapper.selectById(docent.getWxUserId());
            if (wxUser == null) {
                return feignWxUserDto;
            }
        } else {
            return feignWxUserDto;
        }

        BeanUtils.copyProperties(wxUser, feignWxUserDto);
        //查询组织架构
        EnterpriseOrganization enterpriseOrganization = enterpriseOrganizationMapper.selectById(wxUser.getEnterpriseOrganizationId());
        if (enterpriseOrganization != null) {
            feignWxUserDto.setOrganizationName(enterpriseOrganization.getOrganizationName());
        }
        if (enterpriseOrganization != null && enterpriseOrganization.getPid() != null && enterpriseOrganization.getPid() != 0) {
            EnterpriseOrganization last = enterpriseOrganizationMapper.selectById(enterpriseOrganization.getPid());
            feignWxUserDto.setLastOrganizationName(last.getOrganizationName());
        }
        EnterpriseIdentity enterpriseIdentity = enterpriseIdentityMapper.selectById(wxUser.getEnterpriseIdentityId());
        if (enterpriseIdentity != null) {
            feignWxUserDto.setIdentityName(enterpriseIdentity.getIdentityName());
        }
        //查询组织信息
        Enterprise enterprise = enterpriseMapper.selectById(wxUser.getEnterpriseId());
        if (enterprise != null) {
            feignWxUserDto.setEnterpriseName(enterprise.getEnterpriseName());
            feignWxUserDto.setEnterprisePlaceDetail(enterprise.getEnterprisePlaceDetail());
        }
        return feignWxUserDto;
    }

    @Override
    public ReturnVO<WxUserVisitNumStatisticsVo> selectWxUserVisitNumStatisticsVo() {
        WxUserVisitNumStatisticsVo wxUserVisitNumStatisticsVo = new WxUserVisitNumStatisticsVo();
        String startTime = LocalDate.now().minusDays(30).toString();
        String endTime = LocalDate.now().toString();
        //散客访问
        List<VisitNumVo> unEnterpriseVisitNumVos = wxUserStatisticsMapper.selectVisitNumByEnterpriseId(0L, startTime, endTime);
        List<VisitNumVo> enterpriseVisitNumVos = wxUserStatisticsMapper.selectVisitNumByEnterprise(startTime, endTime);
        //展示近30天日期
        List<String> saveTime = Lists.newArrayList();
        LocalDate lastMonthTime = LocalDate.now().minusDays(30);
        for (int i = 0; i < 30; i++) {
            saveTime.add(lastMonthTime.plusDays(i).toString());
        }
        wxUserVisitNumStatisticsVo.setSaveTime(saveTime);
        //近30天总访问量
        List<Long> allVisitNum = Lists.newArrayList();
        //近30天普通用户人数
        List<Long> unEnterpriseVisitNum = Lists.newArrayList();
        //近30天企业用户人数
        List<Long> enterpriseVisitNum = Lists.newArrayList();
        for (String s : saveTime) {
            Long allVisitNumLong = 0L;
            Long unEnterpriseVisitNumLong = 0L;
            Long enterpriseVisitNumLong = 0L;
            //日期匹配
            for (VisitNumVo visitNumVo : unEnterpriseVisitNumVos) {
                if (s.equals(visitNumVo.getSaveTime())) {
                    allVisitNumLong = allVisitNumLong + visitNumVo.getVisitNum();
                    unEnterpriseVisitNumLong = unEnterpriseVisitNumLong + visitNumVo.getVisitNum();
                }
            }
            //日期匹配
            for (VisitNumVo enterpriseVisitNumVo : enterpriseVisitNumVos) {
                if (s.equals(enterpriseVisitNumVo.getSaveTime())) {
                    allVisitNumLong = allVisitNumLong + enterpriseVisitNumVo.getVisitNum();
                    enterpriseVisitNumLong = enterpriseVisitNumLong + enterpriseVisitNumVo.getVisitNum();
                }
            }
            allVisitNum.add(allVisitNumLong);
            unEnterpriseVisitNum.add(unEnterpriseVisitNumLong);
            enterpriseVisitNum.add(enterpriseVisitNumLong);
        }
        //图表
        wxUserVisitNumStatisticsVo.setAllVisitNum(allVisitNum);
        wxUserVisitNumStatisticsVo.setUnEnterpriseVisitNum(unEnterpriseVisitNum);
        wxUserVisitNumStatisticsVo.setEnterpriseVisitNum(enterpriseVisitNum);
        //总数
        Long aLong = wxUserStatisticsMapper.countAllVisitNum(startTime, endTime);
        wxUserVisitNumStatisticsVo.setAllVisitNumLong(aLong);
        wxUserVisitNumStatisticsVo.setUnEnterpriseVisitNumLong(wxUserStatisticsMapper.countEnterpriseVisitNumById(0L, startTime, endTime));
        wxUserVisitNumStatisticsVo.setEnterpriseVisitNumLong(wxUserStatisticsMapper.countEnterpriseVisitNum(startTime, endTime));
        return new ReturnVO<>("近30天用户数据(概况总览)", wxUserVisitNumStatisticsVo);
    }

    @Override
    public ReturnVO<EnterpriseStatisticsVo> selectEnterpriseStatisticsVo() {
        EnterpriseStatisticsVo enterpriseStatisticsVo = new EnterpriseStatisticsVo();
        //展示近30天日期
        List<String> saveTime = Lists.newArrayList();
        LocalDate startTime = LocalDate.now().minusDays(30);
        for (int i = 0; i < 30; i++) {
            saveTime.add(startTime.plusDays(i).toString());
        }
        enterpriseStatisticsVo.setSaveTime(saveTime);
        //入驻企业数
        List<Integer> enterpriseNum = Lists.newArrayList();
        for (String s : saveTime) {
            enterpriseNum.add(enterpriseMapper.selectCount(new LambdaQueryWrapper<Enterprise>()
                    .between(Enterprise::getCreateTime, s, LocalDate.parse(s).plusDays(1).toString())));
        }
        enterpriseStatisticsVo.setEnterpriseNum(enterpriseNum);
        List<Enterprise> enterprises = enterpriseMapper.selectList(new LambdaQueryWrapper<Enterprise>().select(Enterprise::getId));
        enterpriseStatisticsVo.setAllEnterpriseNum(enterpriseMapper.selectCount(new QueryWrapper<>()));
        //各占比的企业数量
        Integer oneHundredNum = 0;
        Integer oneThousandNum = 0;
        Integer twoThousandNum = 0;
        Integer threeThousandNum = 0;
        Integer threeThousandAboveNum = 0;
        for (Enterprise enterpris : enterprises) {
            Integer count = wxUserMapper.selectCount(new LambdaQueryWrapper<WxUser>()
                    .eq(WxUser::getEnterpriseId, enterpris.getId()));
            if (count <= 100) {
                oneHundredNum = oneHundredNum + 1;
            }
            if (100 < count && count <= 1000) {
                oneThousandNum = oneThousandNum + 1;
            }
            if (1000 < count && count <= 2000) {
                twoThousandNum = twoThousandNum + 1;
            }
            if (2000 < count && count <= 3000) {
                threeThousandNum = threeThousandNum + 1;
            }
            if (count > 3000) {
                threeThousandAboveNum = threeThousandAboveNum + 1;
            }
        }
        if (enterprises.size() != 0) {
            enterpriseStatisticsVo.setOneHundred((double) oneHundredNum / enterprises.size() * 100);
            enterpriseStatisticsVo.setOneThousand((double) oneThousandNum / enterprises.size() * 100);
            enterpriseStatisticsVo.setTwoThousand((double) twoThousandNum / enterprises.size() * 100);
            enterpriseStatisticsVo.setThreeThousand((double) threeThousandNum / enterprises.size() * 100);
            enterpriseStatisticsVo.setThreeThousandAbove((double) threeThousandAboveNum / enterprises.size() * 100);
        }
        return new ReturnVO<>("近30天企业数据(概况总览)查询成功", enterpriseStatisticsVo);
    }


    @Override
    public ReturnVO<EnterpriseWxUserVisitNumStatisticsVo> selectEnterpriseWxUserVisitNumStatisticsVo(Long enterpriseId, EnterpriseWxUserVisitNumStatisticsDto enterpriseWxUserVisitNumStatisticsDto) {
        EnterpriseWxUserVisitNumStatisticsVo enterpriseWxUserVisitNumStatisticsVo = new EnterpriseWxUserVisitNumStatisticsVo();
        if (StringUtils.isBlank(enterpriseWxUserVisitNumStatisticsDto.getStartTime()) || StringUtils.isBlank(enterpriseWxUserVisitNumStatisticsDto.getEndTime())) {
            throw new ServiceException("请传入开始和结束时间");
        }
        List<VisitNumVo> visitNumVos = wxUserStatisticsMapper.selectEnterpriseWxUserVisitNumStatisticsVo(enterpriseId, enterpriseWxUserVisitNumStatisticsDto.getStartTime(), enterpriseWxUserVisitNumStatisticsDto.getEndTime());
        List<String> saveTime = Lists.newArrayList();
        //上个月时间
        LocalDate startTime = LocalDate.parse(enterpriseWxUserVisitNumStatisticsDto.getStartTime());
        LocalDate endTime = LocalDate.parse(enterpriseWxUserVisitNumStatisticsDto.getEndTime());
        for (int i = 0; i < endTime.getDayOfYear() - startTime.getDayOfYear(); i++) {
            saveTime.add(startTime.plusDays(i).toString());
        }
        List<Long> visitNumList = Lists.newArrayList();
        for (String s : saveTime) {
            Long visitNum = 0L;
            //日期匹配
            for (VisitNumVo visitNumVo : visitNumVos) {
                if (s.equals(visitNumVo.getSaveTime())) {
                    visitNum = visitNumVo.getVisitNum();
                }
            }
            visitNumList.add(visitNum);
        }
        enterpriseWxUserVisitNumStatisticsVo.setSaveTime(saveTime);
        enterpriseWxUserVisitNumStatisticsVo.setVisitNum(visitNumList);
        return new ReturnVO<>("查询企业登录人数成功", enterpriseWxUserVisitNumStatisticsVo);
    }

    @Autowired
    private DocentMapper docentMapper;


    @Autowired
    private IEnterpriseImproveService enterpriseImproveService;

    @Override
    public ReturnVO<EnterpriseAllStatisticsVo> selectEnterpriseAllStatisticsVo(Long enterpriseId) {
        EnterpriseAllStatisticsVo enterpriseAllStatisticsVo = new EnterpriseAllStatisticsVo();
        ReturnVO<EnterpriseImproveVo> enterpriseImproveVoReturnVO = enterpriseImproveService.selectEnterpriseImproveVo(enterpriseId);
        if ("200".equals(enterpriseImproveVoReturnVO.getCode())) {
            EnterpriseImproveVo data = enterpriseImproveVoReturnVO.getData();
            enterpriseAllStatisticsVo.setWeekendNum(data.getWeekendNum());
            enterpriseAllStatisticsVo.setMonthNum(data.getMonthNum());
            enterpriseAllStatisticsVo.setAllNum(data.getAllNum());
            enterpriseAllStatisticsVo.setWxUserNum(wxUserMapper.selectCount(new LambdaQueryWrapper<WxUser>()
                    .eq(WxUser::getEnterpriseId, enterpriseId)));
            enterpriseAllStatisticsVo.setDocentNum(docentMapper.selectCount(new LambdaQueryWrapper<Docent>()
                    .eq(Docent::getEnterpriseId, enterpriseId)));
            FeignStudyTimeDto feignStudyTimeDto = curriculumApiFeign.selectFeignStudyTimeDto(enterpriseId);
            enterpriseAllStatisticsVo.setStudyTimePerson(feignStudyTimeDto.getStudyTimePerson());
            enterpriseAllStatisticsVo.setSevenStudyTime(feignStudyTimeDto.getSevenStudyTime());
            enterpriseAllStatisticsVo.setCourseNum(curriculumApiFeign.selectCountByEnterpriseId(enterpriseId));
        }
        return new ReturnVO<>("查询该企业的综合数据成功", enterpriseAllStatisticsVo);
    }

    @Override
    public ReturnVO deleteByWxUserId(Long wxUserId) {
        WxUser wxUser = wxUserMapper.selectById(wxUserId);
        Optional.ofNullable(wxUser).orElseThrow(() -> new ServiceException("该用户已经不存在"));
        if (StringUtils.isNotBlank(wxUser.getToken())) {
            if (redisTemplate.hasKey(wxUser.getToken())) {
                redisTemplate.delete(wxUser.getToken());
            }
        }
        wxUserMapper.deleteById(wxUserId);
        return new ReturnVO<>("微信用户删除成功", wxUserId);
    }

    @Override
    public ReturnVO removeEnterprise(Long wxUserId) {
        WxUser wxUser = wxUserMapper.selectById(wxUserId);
        Optional.ofNullable(wxUser).orElseThrow(() -> new ServiceException("该用户已经不存在"));
        if (StringUtils.isNotBlank(wxUser.getToken())) {
            if (redisTemplate.hasKey(wxUser.getToken())) {
                redisTemplate.delete(wxUser.getToken());
            }
        }
        //移除企业身份
        wxUser.setEnterpriseId(0L);
        wxUser.setEnterpriseIdentityId(0L);
        wxUser.setEnterpriseOrganizationId(0L);
        //移除讲师身份
        wxUser.setIsDocent(0);
        Docent docent = docentMapper.selectOne(new LambdaQueryWrapper<Docent>()
                .eq(Docent::getWxUserId, wxUserId));
        if (docent != null) {
            Docent updateDocent = new Docent();
            updateDocent.setDocentStatus(2);
            docentMapper.update(updateDocent, new LambdaUpdateWrapper<Docent>().eq(Docent::getId,docent.getId()).set(Docent::getWxUserId, null));
        }
        wxUserMapper.updateById(wxUser);
        return new ReturnVO<>("踢出企业成功", wxUserId);
    }

}
